﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework;
using GameInterface;
using System.Xml;

namespace GameLayer
{
    public class Sprite : Layer, ICollision<Sprite>, ICloneable, IDisposable
    {
        private int _index;
        private int _minimumIntervalIndexChange = 70;
        private int _nTextures;
        private Rectangle _collisionDefine = Rectangle.Empty;
        public Rectangle CollisionDefine
        {
            get
            {
                return _collisionDefine;
            }
            set
            {
                _collisionDefine = value;
            }
        }

        public int nTextures
        {
            get { return _nTextures; }
            set { _nTextures = value; }
        }
        private Texture2D[] _textures;
        private GameTime _lastIndexChange = new GameTime();
        private GameTime _gameTime = new GameTime();
        public int Index
        {
            get { return _index; }
            set
            {
                if (value > nTextures)
                    throw new IndexOutOfRangeException("index > nTextures");
                _index = value;
            }
        }
        public int MinimumIntervalIndexChange
        {
            get { return _minimumIntervalIndexChange; }
            set { _minimumIntervalIndexChange = value; }
        }
        public Vector2 Size
        {
            get
            {
                Texture2D myTexture = this.Textures[Index];
                return new Vector2(myTexture.Width, myTexture.Height);
            }
        }
        public Texture2D[] Textures
        {
            get { return _textures; }
            set { _textures = value; }
        }

        public Sprite(ContentManager content, String prefixAssets, int n)
        {
            Initialize(content, prefixAssets, n);
        }

        private void Initialize(ContentManager content, String prefixAssets, int n)
        {
            Texture2D[] textures = new Texture2D[n];
            if (n == 1)
            {
                textures[0] = content.Load<Texture2D>(prefixAssets);
            }
            else for (int i = 0; i < n; i++)
                {
                    textures[i] = content.Load<Texture2D>(prefixAssets + i);
                }
            Initialize(textures);
        }
        public Sprite(params Texture2D[] textures)
        {
            Initialize(textures);
        }

        public Sprite(ContentManager content, XmlElement xml)
        {
            int x, y, n;
            String prefixAssets = xml.GetAttribute("prefixAssets");
            if (!int.TryParse(xml.GetAttribute("n"), out n))
            {
                n = 1;
            }
            Initialize(content, prefixAssets, n);
            if (!int.TryParse(xml.GetAttribute("x"), out x))
            {
                x = 0;
            }
            if (!int.TryParse(xml.GetAttribute("y"), out y))
            {
                y = 0;
            }
            if (!int.TryParse(xml.GetAttribute("interval"), out this._minimumIntervalIndexChange))
            {
                this._minimumIntervalIndexChange = 70;
            }
            this.Position = new Vector2(x, y);

        }

        private void Initialize(Texture2D[] textures)
        {
            this.Index = 0;
            this._nTextures = textures.Length;
            this.Textures = textures;
        }

        public void NextFrame()
        {
            if (Enable && DurationFrameChange() > this.MinimumIntervalIndexChange)
            {
                this.Index = (this.Index + 1) % this._nTextures;
                this._lastIndexChange = new GameTime(this._gameTime.TotalGameTime, this._gameTime.ElapsedGameTime);
            }
        }
        public double DurationFrameChange()
        {
            return this._gameTime.TotalGameTime.TotalMilliseconds - this._lastIndexChange.TotalGameTime.TotalMilliseconds;
        }
        public void LastFrame()
        {
            if (Enable && DurationFrameChange() > this.MinimumIntervalIndexChange)
            {
                int lastIndex = this.Index - 1;
                this.Index = lastIndex > -1 ? lastIndex : _nTextures - 1;
                this._lastIndexChange = this._gameTime;
            }

        }

        public Rectangle GetCollisionRectangle()
        {
            int x = (int)Position.X + CollisionDefine.X;
            int y = (int)Position.Y + CollisionDefine.Y;
            int w = (int)Size.X + CollisionDefine.Width;
            int h = (int)Size.Y + CollisionDefine.Height;
            Rectangle bounds = new Rectangle(x, y, w, h);
            return bounds;
        }

        public Boolean CollisionWith(Sprite sprite, bool pixelLevel)
        {
            if (!this.Visible || !sprite.Visible)
            {
                return false;
            }

            if (pixelLevel)
            {
                //    Texture2D myTexture = this.Textures[Index];
                //    Color[] myColors = new Color[myTexture.Width * myTexture.Height];
                //    myTexture.GetData(myColors);

                //    Texture2D yourTexture = sprite.Textures[sprite.Index];
                //    Color[] yourColors = new Color[yourTexture.Width * yourTexture.Height];
                //    yourTexture.GetData(yourColors);

                //    return Utility.IntersectPixels(this.GetCollisionRectangle(), myColors, sprite.GetCollisionRectangle(), yourColors);
                //}
                throw new NotImplementedException();
            }
            else
            {
                if (Vector2.Distance(this.Position, sprite.Position) > 500)
                    return false;
                return this.GetCollisionRectangle().Intersects(sprite.GetCollisionRectangle());
            }
        }

        public object Clone()
        {
            Sprite newSprite = new Sprite(this.Textures);
            newSprite.Enable = this.Enable;
            newSprite.Visible = this.Visible;
            newSprite._index = this._index;
            newSprite.Position = this.Position;
            newSprite.MinimumIntervalIndexChange = this.MinimumIntervalIndexChange;
            newSprite._gameTime = this._gameTime;
            newSprite._lastIndexChange = this._lastIndexChange;

            return newSprite;
        }

        public override void Update(GameTime gameTime)
        {
            this._gameTime = gameTime;
        }

        public override void Draw(GameTime gameTime, SpriteBatch spriteBatch, Viewport viewport)
        {
            if (Visible)
            {
                spriteBatch.Draw(this.Textures[Index], this.Position, Color.White);
            }
        }
        public virtual void Draw(GameTime gameTime, SpriteBatch spriteBatch)
        {
            if (Visible)
            {
                spriteBatch.Draw(this.Textures[Index], this.Position, Color.White);
            }
        }

        public virtual void Draw(GameTime gameTime, SpriteBatch spriteBatch, Color color)
        {
            if (Visible)
            {
                spriteBatch.Draw(this.Textures[Index], this.Position, color);
            }
        }

        public void Draw(GameTime gameTime, SpriteBatch spriteBatch, Vector2 position)
        {
            if (Visible)
            {
                spriteBatch.Draw(this.Textures[Index], position, Color.White);
            }
        }

        public void Draw(GameTime gameTime, SpriteBatch spriteBatch, Rectangle desArea, Color color)
        {
            if (Visible)
            {
                spriteBatch.Draw(this.Textures[Index], desArea, color);
            }
        }

        public void Dispose()
        {
            foreach (var texture in this.Textures)
            {
                if (texture.IsDisposed == false)
                {
                    texture.Dispose();
                }
            }
        }
    }
}